package com.uinnova.product.eam.workable.rsm;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;

/**
 * 资源操作的工具类
 */

@Service
@Slf4j
public class RsmUtils {

    private final static String HUAWEI_SDK_TYPE = "huawei";

    /**
     * obs使用标识
     */
    @Value("${spring.cloud.obs.endpoint:test}")
    private String endpoint;
    @Value("${spring.cloud.obs.access-key:test}")
    private String accessKey;
    @Value("${spring.cloud.obs.secret-key:test}")
    private String secretKey;
    @Value("${spring.cloud.obs.bucketName:test}")
    private String bucketName;
    @Value("${spring.cloud.obs.urlExpireSeconds:3600}")
    private Long urlExpireSeconds;
    @Value("${spring.cloud.obs.region:test}")
    private String region;
    @Value("${spring.cloud.obs.isHttps:N")
    private String isHttps;

    @Value("${rsm.util.sdkType:test}")
    private String sdkType;

    @Value("${local.resource.space}")
    private String localRsmPath;

    @Value("${http.resource.space:}")
    private String urlPath;

    @Value("${obs.rsm.url.prefix:/tarsier-eam/rsm}")
    private String rsmUrlPrefix;

    private RsmBehavior rsmBehavior;

    @PostConstruct
    public void initRsmBehavior() {
        if (HUAWEI_SDK_TYPE.equals(this.sdkType)) {
            this.rsmBehavior = new HuaWeiObsRsmBehavior(this.endpoint, this.accessKey, this.secretKey, this.bucketName, this.urlExpireSeconds);
        }else {
            this.rsmBehavior = new AliyunObsRsmBehavior(this.endpoint, this.accessKey, this.secretKey, this.bucketName, this.urlExpireSeconds, this.region , this.isHttps);
        }

    }

    @PreDestroy
    public void closeClient(){
        this.rsmBehavior.closeClient();
    }

    /**
     * 上传本地文件资源 并指定 objectKey
     * @param objectKey
     * @param file
     * @return
     */
    public boolean uploadRsm(String objectKey, File file) {
        return rsmBehavior.uploadRsm(this.processObjectKey(objectKey),file);
    }

    /**
     * 上传指定的本地文件到对象存储
     * 以文件相对路径为objectKey（相对路径为 去除 本地资源根目录的路径，且objectKey不以"/"为开头）
     * @param file
     * @return
     */
    public boolean uploadRsmFromFile(File file) {
        if(file.isFile()){
            this.uploadRsm(this.processFileObjectKey(file), file);
        }else {
            log.error("对象存储上传指定的本地文件 【失败】：" + file.getAbsolutePath() + "不是目录");
            return false;
        }
        return true;
    }

    /**
     * 上传指定的本地文件夹下的全部文件
     * 以文件相对路径为objectKey（相对路径为 去除 本地资源根目录的路径，且objectKey不以"/"为开头）
     * @param folder
     * @return
     */
    public boolean uploadRsmFromFolder(File folder) {
        if (folder.isDirectory()) {
            File[] files = folder.listFiles();
            for (File file : files) {
                if (file.isDirectory()) {
                    uploadRsmFromFolder(file);
                    continue;
                }
                this.uploadRsmFromFile(file);
            }
        } else {
            log.error("对象存储上传指定的本地文件夹下的全部文件 【失败】：" + folder.getAbsolutePath() + "不是目录");
            return false;
        }
        return true;
    }

    /**
     * 获取资源文件内容
     * @param objectKey
     * @return
     */
    public InputStream downloadRsm(String objectKey) {
        return rsmBehavior.downloadRsm(objectKey);
    }

    /**
     * 下载对象存储中的文件，并更新到本地资源文件夹下
     * @param objectKey
     * @return
     */
    public boolean downloadRsmAndUpdateLocalRsm(String objectKey){

        objectKey = objectKey.startsWith(localRsmPath)?objectKey.replace(localRsmPath,""):objectKey;

        InputStream input = this.downloadRsm(this.processObjectKey(objectKey));

        String targetFilePath = localRsmPath+this.processFilePath(objectKey);
        File targetFile = new File(targetFilePath);

        if(targetFile.exists()){
            targetFile.delete();
        }

        if(!targetFile.getParentFile().exists()){
            targetFile.getParentFile().mkdirs();
        }

        OutputStream out = null;
        try {
            out = Files.newOutputStream(targetFile.toPath());
            byte[] b = new byte[1024];
            int len;
            while ((len=input.read(b)) != -1){
                out.write(b, 0, len);
            }

        } catch (IOException e) {
            log.error("downloadRsmAndUpdateLocalRsm 【写入本地文件操作失败】");
            log.error(e.getMessage());
            throw new RuntimeException(e);
        } finally {
            try {
                out.close();
                input.close();
            } catch (IOException e) {
                log.error("downloadRsmAndUpdateLocalRsm 关闭输入输出流失败");
                log.error(e.getMessage());
            }
        }

        return true;
    }

    /**
     * 删除对象存储中的资源
     * @param objectKey
     * @return
     */
    public boolean deleteRsm(String objectKey) {
        try{
            return rsmBehavior.deleteRsm(this.processObjectKey(objectKey));
        }catch (Exception e){
            log.error("RsmUtils 删除资源失败： " + e.getMessage());
            return false;
        }
    }

    /**
     * 删除对象存储中对应的文件
     * @param file
     * @return
     */
    public boolean deleteRsmByFile(File file) {
        String objectKey = this.processFileObjectKey(file);
        return this.deleteRsm(objectKey);
    }

    /**
     * 删除对象存储中对应的文件夹以及其下文件
     * @param folder
     * @return
     */
    public boolean deleteRsmByFolder(File folder){
        try {
            if(folder.isDirectory()){
                File[] files = folder.listFiles();  // 获取目录下所有文件和子目录
                for (File file : files) {
                    if (file.isDirectory()) {
                        deleteRsmByFolder(file);
                        continue;
                    }
                    this.deleteRsmByFile(file);
                }
            }
            return true;
        }catch (Exception e){
            log.error("RsmUtils 删除资源失败： " + e.getMessage());
            return false;
        }

    }

    /**
     * 获取资源文件的可访问链接
     * @param objectKey
     * @return
     */
    public String getRsmUrlWithAccess(String objectKey) {
        return rsmBehavior.getRsmUrlWithAccess(this.processObjectKey(objectKey));
    }

    /**
     * 生成文件的objectKey
     * @param file
     * @return
     */
    public String processFileObjectKey(File file){
        String path = file.getAbsolutePath();
        return this.processObjectKey(path);
    }

    /**
     * 处理bojectKey，检查objectKey是否以"/"开头
     * 删除objectKey中开头的"/"
     * @param objectKey
     * @return
     */
    public String processObjectKey(String objectKey){

        if(StringUtils.isNotBlank(objectKey)){

            if(objectKey.startsWith(localRsmPath)){
                objectKey = objectKey.replace(localRsmPath,"");
            }else if(objectKey.startsWith(urlPath)){
                objectKey = objectKey.replace(urlPath,"");
            }else if(objectKey.startsWith(rsmUrlPrefix)){
                objectKey = objectKey.replace(rsmUrlPrefix,"");
            }

        if(objectKey.startsWith("/")){
                objectKey = objectKey.substring(1);
                return this.processObjectKey(objectKey);
            }
        }
        return objectKey;
    }

    /**
     * 处理文件路径
     * 为文件路径开头增加"/"
     * @param filePath
     * @return
     */
    public String processFilePath(String filePath){
        if(StringUtils.isNotBlank(filePath)){
            filePath = filePath.startsWith(localRsmPath)?filePath:"/"+filePath;
        }
        return filePath;
    }

}
